#pragma once

#include <CtrlLib/CtrlLib.h>
#include <Core/Core.h>
#include "Events.hpp"
#include "util.hpp"

using namespace Upp;

class MyCoEvent {
	Mutex             lock;
	ConditionVariable cv;

public:
	void Wait(int timeout_ms)   { lock.Enter(); cv.Wait(lock, timeout_ms); lock.Leave(); }
	void Wait()                 { lock.Enter(); cv.Wait(lock); lock.Leave(); }
	void Broadcast()            { cv.Broadcast(); }
};


struct MyEvent: ValueType<MyEvent, 10001> {
    int event_id;
    MyTime event_time;
    Vector<String> event_data;

    MyEvent() {event_id = Null;}
    MyEvent(const Nuller &) { event_id = Null; } 
    MyEvent(int event_id): event_id(event_id) {event_time = MyGetSysTime();}
    MyEvent(const MyEvent &e, int type) 
    {
        event_id = e.event_id;
        event_data <<= e.event_data;
        event_time = e.event_time;
    }

    void Add(const String &data) { event_data.Add(data); }
    void Add(const char *data) {  event_data.Add(String(data)); }

    operator Value() const { return RawDeepToValue(*this); }
    MyEvent(const Value& v) { const MyEvent &e = v.Get<MyEvent>(); event_id = e.event_id; event_data = clone(e.event_data); event_time = e.event_time; }

    String ToString() const { return " Event:" + AsString(event_id) + " Data(Hex):" + AsHexString(event_data.ToString()); }

    unsigned GetHashValue() const { return CombineHash() << event_id << event_data; }

    void Serialize(Stream& s) { s % event_id % event_data; }

    bool operator==(const MyEvent& b) const { return event_id == b.event_id && event_data == b.event_data; }
    bool IsNullInstance() const { return IsNull(event_id);}
    int Compare(const MyEvent& b) const { return SgnCompare(event_id, b.event_id) || SgnCompare(event_data, b.event_data); }
    
    void Jsonize(JsonIO& jio) { jio("event_id", event_id)("event_data", event_data); }
    void Xmlize(XmlIO& xio) {xio("event_id", event_id)("event_data", event_data); }
};

//event queue
typedef BiVector<Value> MyEventQueueType;
// typedef Event<const MyEvent&> MyEventListener;
typedef CallbackN<const MyEvent&> MyEventListener;

//event table/map to record event listener
typedef VectorMap<uint32_t, Vector<MyEventListener>> MyEventTable;

//event queue class
class MyEventQueue
{
public:
    enum {ALL_EVENT = 0xFFFF};
    MyEventQueue() {}
    ~MyEventQueue() { ProcessEvent(); }

    //register listener
    void Register(int event_id, MyEventListener& listener);
    void Unregister(int event_id, MyEventListener& listener);

    void PostEvent(const MyEvent& e);

    //process event
    void ProcessEvent(void);

    //global event queue
    static MyEventQueue& GetGlobalEventQueue(void) { static MyEventQueue s_event_queue; return s_event_queue; }
private:
    MyEventQueueType m_queue;
    MyEventTable m_table;
};

void StartEventQueueThread(void);
void MyPostEvent(int event_id, std::initializer_list<String> data);
void MyRegisterEvent(int event_id, MyEventListener&& listener);

